/**
 * Copyright(c) 2014 Xunton Solutions
 *
 * History:
 *   15-1-9 上午11:21 Created by dwzhang
 */
package com.jade.framework.base.vfile.impl;

import java.io.*;
import java.util.UUID;

import com.jade.framework.base.JadeSystem;
import com.jade.framework.base.util.FileTypeUtils;
import com.jade.framework.base.util.UniqueID;
import com.jade.framework.base.vfile.VFileInfo;
import com.jade.framework.base.vfile.VFileManager;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 实际文件系统的方式来管理。
 *
 * @author <a href="mailto:dwzhang@xunton.com">dwzhang</a> 
 * @version 1.0 15-1-9 上午11:21
 */
public class FsFileManager
        implements VFileManager
{
    public static final String TYPE = "fs";
    private String home;
    private int level = 2;
    private int count = 512;
    private boolean orgByDataType = true;
    private Log log = LogFactory.getLog(FsFileManager.class);

    public void setHome(String home)
    {
        this.home = home;
    }

    public void setLevel(int level)
    {
        this.level = level;
    }

    public void setCount(int count)
    {
        this.count = count;
    }

    public void setOrgByDataType(boolean orgByDataType)
    {
        this.orgByDataType = orgByDataType;
    }

    public void init()
    {
        if (StringUtils.isNotBlank(home)) {
            home = JadeSystem.getHome() + "/data";
        }
    }

    protected String getHomePath(String dataType)
    {
        return home + File.separator + (orgByDataType ? dataType : "");
    }

    public VFileInfo uploadFile(String dataType, File localFile)
            throws IOException
    {
        VFileInfo info = new VFileInfo();
        info.setDataType(dataType);
        info.setFileName(localFile.getName());
        info = setInfo(info);
        File file = new File(getHomePath(dataType), info.getFileId());
        FileUtils.copyFile(localFile, file);
        info.setSize(localFile.length());
        return info;
    }

    protected VFileInfo setInfo(VFileInfo info)
    {
        info.setType(TYPE);
        if (StringUtils.isNotBlank(info.getFileId())) {
            File file = new File(getHomePath(info.getDataType()), info.getFileId());
            info.setFileName(file.getName());
            info.setSize(file.length());
            info.setLastModified(file.lastModified());
        }
        else {
            String fileName = info.getFileName();
            String uuid = UUID.randomUUID().toString();
            String extName = null;
            if (StringUtils.isNotBlank(fileName)) {
                extName = FilenameUtils.getExtension(fileName);
            }
            info.setFileName(extName == null ? uuid : (uuid + "." + extName));
            String fileId = "";
            for (int i = 0; i < level; i++) {
                fileId += File.separator;
                fileId += UniqueID.nextInt(count);
            }
            info.setFileId(fileId + File.separator + info.getFileName());
        }

        if (StringUtils.isBlank(info.getContentType())) {
            info.setContentType(FileTypeUtils.getContentType(info.getFileName()));
        }
        return info;
    }

    public VFileInfo uploadFile(VFileInfo info, InputStream is)
            throws IOException
    {
        info = setInfo(info);
        File file = new File(getHomePath(info.getDataType()), info.getFileId());
        FileUtils.copyInputStreamToFile(is, file);
        info.setSize(file.length());
        return info;
    }

    public VFileInfo uploadFile(VFileInfo info, byte[] data, int offset, int length)
            throws IOException
    {
        ByteArrayInputStream bais = new ByteArrayInputStream(data, offset, length);
        return uploadFile(info, bais);
    }

    public VFileInfo getFileInfo(String dataType, String id)
            throws IOException
    {
        VFileInfo info = new VFileInfo();
        info.setDataType(dataType);
        info.setFileId(id);
        return setInfo(info);
    }

    public void downloadFile(String dataType, String id, File localFile)
            throws IOException
    {
        File file = new File(getHomePath(dataType), id);
        FileUtils.copyFile(file, localFile);
    }

    public void downloadFile(String dataType, String id, OutputStream os)
            throws IOException
    {
        File file = new File(getHomePath(dataType), id);
        FileUtils.copyFile(file, os);
    }

    public void downloadFile(String dataType, String id, OutputStream os, long offset, long length)
            throws IOException
    {
        File file = new File(getHomePath(dataType), id);
        FileInputStream fis = new FileInputStream(file);
        try {
            IOUtils.copyLarge(fis, os, offset, length);
        }
        finally {
            IOUtils.closeQuietly(fis);
        }
    }

    public void downloadFile(VFileInfo info, OutputStream os)
            throws IOException
    {
        File file = new File(getHomePath(info.getDataType()), info.getFileId());
        FileUtils.copyFile(file, os);
    }

    public void downloadFile(VFileInfo info, OutputStream os, long offset, long length)
            throws IOException
    {
        File file = new File(getHomePath(info.getDataType()), info.getFileId());
        FileInputStream fis = new FileInputStream(file);
        try {
            IOUtils.copyLarge(fis, os, offset, length);
        }
        finally {
            IOUtils.closeQuietly(fis);
        }
    }

    public void downloadFile(VFileInfo info, File localFile)
            throws IOException
    {
        File file = new File(getHomePath(info.getDataType()), info.getFileId());
        FileUtils.copyFile(file, localFile);
    }

    public VFileInfo removeFile(String dataType, String id)
            throws IOException
    {
        VFileInfo info = new VFileInfo();
        info.setDataType(dataType);
        info.setFileId(id);
        info = setInfo(info);
        File file = new File(getHomePath(info.getDataType()), info.getFileId());
        if (file.exists()) {
            FileUtils.forceDelete(file);
        }
        return info;
    }

    public VFileInfo removeFileQuitely(String dataType, String id)
    {
        try {
            return removeFile(dataType, id);
        }
        catch (Throwable t) {
            log.warn("Can't remove file:" + dataType + " " + id, t);
            return null;
        }
    }
}
